#Python's reentrant lock
A regular mutex lock can only be acquired once. If the same thread tries to acquire it again before releasing it, it will block and potentially deadlock. Sometimes, however, a thread needs to perform multiple operations on a shared variable, and if the lock is acquired multiple times, it may lead to permanent blocking.
For example:
from threading import Lock
# Counter
class Counter:
def __init__(self):
self.__value = 0
self.__lock = Lock()
# Increment the counter
def increase(self):
with self.__lock: # Re-acquiring the lock
self.__value += 1
# Get the value and auto-increment
def touch(self):
value = 0
with self.__lock: # Acquire lock
value = self.__value
self.increase()
return value
# Global variable
counter = Counter()
# Invocation
counter.touch()
print('Done')
In large projects, it's often hard to ensure whether a lock has already been acquired within a function or interface. In such cases, you can use a reentrant lock (ReentrantLock
).
A reentrant lock allows the same thread to acquire the lock multiple times. It must also release it the same number of times for the lock to be fully released.
In Python, use the RLock
class from the threading
module to create a reentrant lock. It provides acquire
and release
methods and supports the with
statement.
The previous code can be modified as follows:
from threading import RLock
# Counter
class Counter:
def __init__(self):
self.__value = 0
self.__lock = RLock()
# Increment the counter
def increase(self):
with self.__lock: # Re-acquire lock
self.__value += 1
# Get the value and auto-increment
def touch(self):
value = 0
with self.__lock: # Acquire lock
value = self.__value
self.increase()
return value
# Global variable
counter = Counter()
# Invocation
counter.touch()
print('Done')